/*    file: H264NaluParser.cpp
 *    desc:
 * 
 * created: 2014-06-16 23:11:30
 *  author: zhengchuanjiang
 * version: 1.0
 * company: 
 */

#include "H264NaluParser.h"


H264NaluParser::H264NaluParser()
{

}

H264NaluParser::~H264NaluParser()
{

}

const uint8_t H264NaluParser::s_startCode[START_CODE_LENGTH] = { 0, 0, 0, 1};


const uint8_t* H264NaluParser::getStartCode()
{
    return s_startCode;

}


bool H264NaluParser::startWithH264Code(const uint8_t* data, size_t length)
{
    if (length < 4)
    {
        return false;
    }

    if (data[0] == 0 && data[1] == 0)
    {
        if (data[2] == 1)
        {
            return true;
        }
        else if ((data[2] == 0) && (data[3] == 1))
        {
            return true;
        }
    }

    return false;
}


size_t H264NaluParser::findH264StartCode(const uint8_t* data, size_t length, size_t start)
{
    for (size_t i = start; i < length - 4; ++ i)
    {
        if (data[i] == 0)
        {
            if (startWithH264Code(&data[i], length - i))
            {
                return i;
            }
        }
    }
    return -1;
}

void H264NaluParser::insertStartCode(std::string& data)
{
    data.insert(0, (const char*)s_startCode, START_CODE_LENGTH);
}


bool H264NaluParser::parseNalu(const uint8_t* data, size_t length, NaluPacket& pkt)
{
    if ((data[0] == 0) && (data[1] == 0))
    {
        if (data[2] == 1)
        {
            pkt.prefix = 3;
        }
        else if ((data[2] == 0) && (data[3] == 1))
        {
            pkt.prefix = 4;
        }
        else
        {
            return false;
        }
    }

    pkt.data = data + pkt.prefix;
    pkt.length = length - pkt.prefix;
    pkt.type = (pkt.data[0] & 0x1F);

    return true;
}

int H264NaluParser::parseNaluType(uint8_t data)
{
    return (data & 0x1F);
}

size_t H264NaluParser::hexToData(const std::string& hexStr, std::string& data)
{
    size_t length = 0;
    int c = 0;
    int value = 1;
    for (size_t i = 0; i < hexStr.size(); i ++)
    {
        c = toupper((unsigned char)hexStr[i]);
        if (c >= '0' && c <= '9')
            c = c - '0';
        else if (c >= 'A' && c <= 'F')
            c = c - 'A' + 10;
        else
            break;
        value = (value << 4) | c;
        if (value & 0x100)
        {
            data.append(1, value);

            length ++;
            value = 1;
        }
    }
    return length;
}

bool H264NaluParser::parseProfileLevel(const std::string& hexStr, int& profile, int& level)
{
    bool done = false;
    if (hexStr.size() == 6)
    {
        std::string data;
        hexToData(hexStr, data);

        if (data.size() == 3)
        {
            profile = data[0];
            level = data[2];
        }

        done = true;
    }
    return done;
}
